/*
 *  OWLConverter.java
 *
 *  Copyright (c) 2010 Dariusz Leniowski. All Rights Reserved.
 *
 *  Redistribution and use in source and binary forms, with or without 
 *  modification, are permitted provided that the following conditions 
 *  are met:
 *
 *  1. Redistributions of source code must retain the above copyright 
 *     notice, this list of conditions and the following disclaimer.
 *
 *  2. Redistributions in binary form must reproduce the above copyright 
 *     notice, this list of conditions and the following disclaimer 
 *     in the documentation and/or other materials provided with 
 *     the distribution.
 *
 *  3. The name of the author may not be used to endorse or promote 
 *     products derived from this software without specific prior 
 *     written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
 *  THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 *  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
 *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
 *  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
 *  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */


package separ.type;

import java.util.*;
import java.util.regex.*;
import java.io.*;
import java.math.BigInteger;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URI;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.io.OWLXMLOntologyFormat;
import org.semanticweb.owlapi.model.*;
import org.semanticweb.owlapi.vocab.OWLRDFVocabulary;

public class OWLConverter {
	static private OWLOntologyManager  manager;
	static private OWLOntology ontology;
	static private OWLDataFactory dataFactory;
	static private IRI base;
	static private IRI physicalAddress;
	static private Map<OWLClass,Integer> clsCToI;
	static private Map<Integer,OWLClass> clsIToC;
	static private Integer clsN;
	static private BigInteger clsNothingE;
	static private BigInteger clsNothingThingE;
	static private Map<Integer,BigInteger> clsIToE;
	static private Map<Integer,Set<Integer>> clsISub;
	static private Map<Integer,Set<Integer>> clsISuper;
	static private Map<Integer,Set<String>> clsComments;
	static private Map<Integer,Set<String>> clsAnnotations;
	static private Map<Integer,Map<String,Set<String>>> clsProperties;
	static private Map<Integer,Set<String>> clsValues;
	static private Map<String,Set<Integer>> indTypes;
	static private Map<String,Set<String>>  indExprs;

	static private Integer numberSpecial = 3; // Number of classes not represented by bits
	static private Integer numberOfPredefined = 5;
	static private Integer numberThing = 1;        // Top
	static private Integer numberNothing = 2;      // Bottom
	static private Integer numberNothingThing = 3; // This is Nothing, but with no properties
	static private Integer numberThingNothing = 4; // This is just normal class, only every its property is Nothing
	static private Integer numberUnknown = 5;      // Unknown is just a normal class


	public static void main(String args[])
	{
		if (args.length == 0) System.err.println("No ontology given!");
		else try {
			System.out.println("Opening ontology from: " + args[0]);
			physicalAddress = IRI.create(args[0]);
			manager = OWLManager.createOWLOntologyManager();
			ontology = manager.loadOntologyFromOntologyDocument(physicalAddress);
			base = ontology.getOntologyID().getDefaultDocumentIRI();
			dataFactory = manager.getOWLDataFactory();
			System.out.println("Opened ontology: " + base.toString());
			generateClsMap();
			generateClsType();
			generateClsData();
			generateClsDict();
			System.out.println("Processed:");
			System.out.println("  " + clsN.toString() + " classes");
			System.out.println("  " + (new Integer(ontology.getIndividualsInSignature().size())).toString() + " individuals");
			System.out.println("Generated files:");
			System.out.println("  ClsType.hs");
			System.out.println("  ClsData.hs");
			System.out.println("  ClsDict.hs");
			System.out.println("Exiting");

		/*} catch (java.net.MalformedURLException e) {
			System.err.println("Invalid URL: " + e.getMessage());
		} catch (java.net.URISyntaxException e) {
			System.err.println("Invalid URI: " + e.getMessage()); */
		} catch (OWLOntologyCreationException e) {
			System.err.println("The ontology could not be created: " + e.getMessage());
		}
	}

	public static String sValue(String sValue) {
		String result = sValue;
		Map<String,String> ids = 
			new TreeMap<String,String>(
				new Comparator<String>() {
					public int compare(String a, String b) {
						if (a.charAt(0) == '!' && b.charAt(0) != '!') return 1;
						if (a.charAt(0) != '!' && b.charAt(0) == '!') return -1;
						if (a.length() > b.length()) return -1;
						if (a.length() < b.length()) return 1;
						else return b.compareTo(a);
					}
				}
			);
		Pattern var = Pattern.compile("\\$[_a-zA-ZąćęłńóśżźĄĆĘŁŃÓŚŻŹ][_A-Za-ząćęłńóśżźĘÓĄŚŁŻŹĆŃ0-9]*");
		Pattern ident = Pattern.compile("[_a-zA-ZąćęłńóśżźĄĆĘŁŃÓŚŻŹ~@][_A-Za-ząćęłńóśżźĄĆĘŁŃÓŚŻŹ0-9]*");
		Integer i = 1;
		Matcher varM = var.matcher(result);
		while (varM.find()) {
			String id = varM.group();
			ids.put("\\"+id,"("+i.toString()+"%)");
			i ++;
		}
		ids.put("\\$self","#1");
		ids.put("`sup`","#2");
		ids.put("`inf`","#3");
		for (Map.Entry<String,String> e : ids.entrySet())
			result = result.replaceAll(e.getKey(),e.getValue());
		ids.clear();
		Matcher identM = ident.matcher(result);
		i = 1;
		while (identM.find()) {
			String id = identM.group();
			ids.put(id,"!"+i.toString()); 
			// exclamation mark is sorted before any other characters
			ids.put("!"+i.toString(),"\"" + id + "\"");
			i ++;
		}
		ids.put("var","#4");
		for (Map.Entry<String,String> e : ids.entrySet())
			result = result.replaceAll(e.getKey(),e.getValue());
		result = result.replaceAll(":","`is`");
		result = result.replaceAll("%","::Int");
		result = result.replaceAll("\\["," `sp` ");
		result = result.replaceAll("\\s*=\\s*"," `val` (");
		result = result.replaceAll("\\]",")");
		result = result.replaceAll("\\."," `gp` ");
		result = result.replaceAll("\\{","[t ");
		result = result.replaceAll(",",", t ");
		result = result.replaceAll("\\}","]");
		result = result.replaceAll("\n"," ");
		result = result.replaceAll("\\s+"," ");
		result = result.replaceAll("#1","self");
		result = result.replaceAll("#2","`sup`");
		result = result.replaceAll("#3","`inf`");
		result = result.replaceAll("#4","var");
		result = "toType("+result.trim()+")";
		return result;
	}

	public static void generateClsMap() {
		// get the ontologies
		Set<OWLClass> classes = ontology.getClassesInSignature();
		// and map of number of children for topological sort
		Map<OWLClass,Integer> nchildren = new HashMap<OWLClass,Integer>();
		// set of classes children of which have been processed
		Set<OWLClass> free = new HashSet<OWLClass>();
		OWLClass nothingThing = dataFactory.getOWLClass(getIRI("NothingThing"));
		OWLClass thingNothing = dataFactory.getOWLClass(getIRI("ThingNothing"));
		OWLClass unknown      = dataFactory.getOWLClass(getIRI("Unknown"));
		clsN = classes.size() + numberOfPredefined;
		for (OWLClass c : classes) {
			if (c.isOWLThing()) clsN -= 1;
			if (c.isOWLNothing()) clsN -= 1;
			if (c.equals(nothingThing)) clsN -= 1;
			if (c.equals(thingNothing)) clsN -= 1;
			if (c.equals(unknown)) clsN -= 1;
			int i = c.getSubClasses(ontology).size();
			nchildren.put(c,new Integer(i));
			if (i == 0 && !c.isOWLThing() && !c.isOWLNothing() &&
						  !c.equals(nothingThing) && !c.equals(thingNothing) &&
						  !c.equals(unknown)) free.add(c); // add all classes but predefined
		}
		clsIToC = new TreeMap<Integer,OWLClass>();
		clsCToI = new TreeMap<OWLClass,Integer>();
		Integer id = new Integer(numberOfPredefined+1);
		while (!free.isEmpty()) {
			OWLClass c = any(free);
			free.remove(c);
			clsCToI.put(c,id);
			clsIToC.put(id,c);
			id ++;
			for (OWLClassExpression o : c.getSuperClasses(ontology)) {
				OWLClass d = o.asOWLClass();
				int i = nchildren.get(d)-1;
				nchildren.put(d,new Integer(i));
				if (i == 0 && !d.isOWLThing() && !d.isOWLNothing() &&
							  !d.equals(nothingThing) && !d.equals(thingNothing) &&
							  !d.equals(unknown)) 
					free.add(d); // add all classes but predefined
			}
		}
		if (clsCToI.size() != clsN-numberOfPredefined) {
			System.out.println(classes.size());
			System.out.println(clsCToI.size());
			throw new IllegalArgumentException("Cycle in classes graph!");
		}
		// add predefined
		clsIToC.put(numberThing, dataFactory.getOWLThing());
		clsIToC.put(numberNothing, dataFactory.getOWLNothing());
		clsIToC.put(numberNothingThing, nothingThing);
		clsIToC.put(numberThingNothing, thingNothing);
		clsIToC.put(numberUnknown,      unknown);
		// some constants
		clsNothingE = BigInteger.ZERO.setBit(clsN-numberSpecial).subtract(BigInteger.ONE);
		clsNothingThingE = BigInteger.ZERO.setBit(clsN-numberSpecial).subtract(BigInteger.ONE).
										   clearBit(numberThingNothing-1-numberSpecial);
		clsISuper = new TreeMap<Integer,Set<Integer>>();
		clsISub = new TreeMap<Integer,Set<Integer>>();
		for (int i = 1; i <= clsN; i ++) {
			OWLClass c = clsIToC.get(i);
			Set<Integer> sup = new TreeSet<Integer>();
			Set<Integer> sub = new TreeSet<Integer>();
			// for now we don't allow user subclasses or superclasses for NothingThing and ThingNothing
			// if needed, it can be done with gcd [UserClass,ThingNothing]
			if (!c.isOWLThing() && !c.equals(thingNothing)) 
			for (OWLClassExpression o : c.getSuperClasses(ontology)) {
				OWLClass d = o.asOWLClass();
				if (d.isOWLThing()) ; // do nothing // sup.add(new Integer(numberThing));
				else if (d.isOWLNothing()) ; // sup.add(new Integer(numberNothing));
				else if (d.equals(nothingThing)) ; // sup.add(new Integer(numberNothingThing));
				else if (d.equals(thingNothing)) ; // sup.add(new Integer(numberThingNothing));
				else if (d.equals(unknown))      sup.add(new Integer(numberUnknown));
				else {
					int j = clsCToI.get(d);
					sup.add(j);
				}
			}
			if (!c.isOWLNothing() && !c.equals(nothingThing) && !c.equals(thingNothing))
			for (OWLClassExpression o : c.getSubClasses(ontology)) {
				OWLClass d = o.asOWLClass();
				if (d.isOWLThing()) ; // do nothing // sub.add(new Integer(numberThing));
				else if (d.isOWLNothing()) ; // sub.add(new Integer(numberNothing));
				else if (d.equals(nothingThing)) ; // sub.add(new Integer(numberNothingThing));
				else if (d.equals(thingNothing)) ; // sub.add(new Integer(numberThingNothing));
				else if (d.equals(unknown))      sub.add(new Integer(numberUnknown));
				else {
					int j = clsCToI.get(d);
					sub.add(j);
				}
			}
			if (sup.isEmpty() && !c.isOWLThing() && !c.isOWLNothing()) {
				sup.add(new Integer(numberThing));
				clsISub.get(numberThing).add(i);
			}
			if (sub.isEmpty() && !c.isOWLNothing() && !c.isOWLThing() &&
								 !c.equals(nothingThing) && !c.equals(thingNothing)) {
				sub.add(new Integer(numberNothingThing));
				clsISuper.get(numberNothingThing).add(i);
			}
			if (sub.isEmpty() && c.equals(nothingThing)) {
				sub.add(new Integer(numberNothing));
				clsISuper.get(numberNothing).add(i);
			}
			if (sub.isEmpty() && c.equals(thingNothing)) {
				sub.add(new Integer(numberNothing));
				clsISuper.get(numberNothing).add(i);
			}
			clsISuper.put(i,sup);
			clsISub.put(i,sub);
		}
		clsIToE = new TreeMap<Integer,BigInteger>();
		clsIToE.put(numberThingNothing,BigInteger.ZERO.setBit(numberThingNothing-1-numberSpecial));
		clsIToE.put(numberUnknown,BigInteger.ZERO.setBit(numberUnknown-1-numberSpecial));
		for (int i = clsN; i > numberSpecial; i --) {
			BigInteger bi = BigInteger.ZERO.setBit(i-1-numberSpecial);
			for (Integer j : clsISuper.get(i)) {
				if (j <= numberSpecial) continue; // Thing and Nothing and NothingThing
				bi = bi.or(clsIToE.get(j));
			}
			clsIToE.put(i,bi);
		}
		//second run, because we don't know where Unknown should be
		for (int i = clsN; i > numberSpecial; i --) {
			BigInteger bi = BigInteger.ZERO.setBit(i-1-numberSpecial);
			for (Integer j : clsISuper.get(i)) {
				if (j <= numberSpecial) continue; // Thing and Nothing and NothingThing
				bi = bi.or(clsIToE.get(j));
			}
			clsIToE.put(i,bi);
		}
		clsComments = new TreeMap<Integer,Set<String>>();
		clsAnnotations = new TreeMap<Integer,Set<String>>();
		clsValues = new TreeMap<Integer,Set<String>>();
		clsProperties = new TreeMap<Integer,Map<String,Set<String>>>();
		for (int i = 1; i <= clsN; i ++) {
			clsComments.put(i,getComments(clsIToC.get(i)));
			clsValues.put(i,getValues(clsIToC.get(i)));
			clsAnnotations.put(i,getAnnotations(clsIToC.get(i)));
			clsProperties.put(i,getProperties(clsIToC.get(i)));
		}
		indTypes = new TreeMap<String,Set<Integer>>();
		indExprs = new TreeMap<String,Set<String>>();
		for (OWLIndividual i : ontology.getIndividualsInSignature()) {
			Set<String> ts = getIndividualProperty(i,"text");
			Set<String> es = getIndividualProperty(i,"expression");
			Set<OWLClass> cs = getIndividualTypes(i);
			for (String t : ts) {
				if (indExprs.get(t) == null) {
					indExprs.put(t,new TreeSet<String>());
					indTypes.put(t,new TreeSet<Integer>());
				}
				for (String e : es) indExprs.get(t).add("\""+escape(e)+"\"");
				for (OWLClass c : cs) {
					Integer j;
					if (c.isOWLThing()) j = numberThing;
					else if (c.isOWLNothing()) j = numberNothing;
					else j = clsCToI.get(c);
					indTypes.get(t).add(j);
				}
			}
		}
	}

	public static void generateClsType() {
		PrintWriter out = null;
		try {			
			out = new PrintWriter("ClsType.hs");

out.println("{-");
out.println(" -  Separ, Type/ClsType.hs");
out.println(" -");
out.println(" -  Copyright (c) 2010 Dariusz Leniowski. All Rights Reserved.");
out.println(" -");
out.println(" -  Redistribution and use in source and binary forms, with or without ");
out.println(" -  modification, are permitted provided that the following conditions ");
out.println(" -  are met:");
out.println(" -");
out.println(" -  1. Redistributions of source code must retain the above copyright ");
out.println(" -     notice, this list of conditions and the following disclaimer.");
out.println(" -");
out.println(" -  2. Redistributions in binary form must reproduce the above copyright ");
out.println(" -     notice, this list of conditions and the following disclaimer ");
out.println(" -     in the documentation and/or other materials provided with ");
out.println(" -     the distribution.");
out.println(" -");
out.println(" -  3. The name of the author may not be used to endorse or promote ");
out.println(" -     products derived from this software without specific prior ");
out.println(" -     written permission.");
out.println(" -");
out.println(" -  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ");
out.println(" -  \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ");
out.println(" -  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ");
out.println(" -  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ");
out.println(" -  THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, ");
out.println(" -  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ");
out.println(" -  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ");
out.println(" -  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ");
out.println(" -  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ");
out.println(" -  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING ");
out.println(" -  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ");
out.println(" -  POSSIBILITY OF SUCH DAMAGE.");
out.println(" -");
out.println(" -}");
out.println("");
out.println("-- Module ClsType");
out.println("-- Autogenerated, do not edit");
out.println("");
out.println("module Type.ClsType where");
out.println("");
out.println("import qualified GHC.Read as GR");
out.println("import qualified Text.Read.Lex as Lex");
out.println("import qualified Text.ParserCombinators.ReadPrec as RP");
out.println("import qualified Data.List as List");
out.println("import Data.Bits");
out.println("");
out.println("data ClsType = C Int Integer deriving (Eq,Ord)");
out.println("");
out.println("clsN :: Int");
out.println("clsN = " + clsN.toString());
out.println("clsNSpecial :: Int");
out.println("clsNSpecial = " + numberSpecial.toString());
out.println("");
out.println("clsGetAllI :: [Int]");
out.println("clsGetAllI = [1.."+ clsN.toString() + "]");
out.println("");
out.println("clsGetAll :: [ClsType]");
out.println("clsGetAll = map clsIToCls clsGetAllI");
out.println("");
out.println("clsThingI :: Int");
out.println("clsThingI = " + numberThing);
out.println("clsThing :: ClsType");
out.println("clsThing = (C clsThingI 0)");
out.println("clsNothingI :: Int");
out.println("clsNothingI = " + numberNothing);
out.println("clsNothing :: ClsType");
out.println("clsNothing = (C clsNothingI 0)");
out.println("clsNothingThingI :: Int");
out.println("clsNothingThingI = " + numberNothingThing);
out.println("clsNothingThing :: ClsType");
out.println("clsNothingThing = (C clsNothingThingI 0)");
out.println("clsThingNothingI :: Int");
out.println("clsThingNothingI = " + numberThingNothing);
out.println("clsThingNothing :: ClsType");
out.println("clsThingNothing = (C clsThingNothingI 0)");
out.println("clsUnknownI :: Int");
out.println("clsUnknownI = " + numberUnknown);
out.println("clsUnknown :: ClsType");
out.println("clsUnknown = (C clsUnknownI 0)");
out.println("");
out.println("clsIsThing :: ClsType -> Bool");
out.println("clsIsThing (C " + numberThing + " 0) = True");
out.println("clsIsThing _ = False");
out.println("");
out.println("clsIsNothing :: ClsType -> Bool");
out.println("clsIsNothing (C " + numberNothing + " 0) = True");
out.println("clsIsNothing (C 0 (-1)) = True");
out.println("clsIsNothing (C 0 " + clsNothingE.toString() + ") = True");
out.println("clsIsNothing _ = False");
out.println("");
out.println("clsIsNothingThing :: ClsType -> Bool");
out.println("clsIsNothingThing (C " + numberNothingThing + " 0) = True");
out.println("clsIsNothingThing (C 0 " + clsNothingThingE.toString() + ") = True");
out.println("clsIsNothingThing _ = False");
out.println("");
out.println("clsIsThingNothing :: ClsType -> Bool");
out.println("clsIsThingNothing (C " + numberThingNothing + " 0) = True");
out.println("clsIsThingNothing (C 0 " + clsIToE.get(numberThingNothing).toString() + ") = True");
out.println("clsIsThingNothing _ = False");
out.println("");
out.println("clsIsUnknown :: ClsType -> Bool");
out.println("clsIsUnknown (C " + numberUnknown + " 0) = True");
out.println("clsIsUnknown (C 0 " + clsIToE.get(numberUnknown).toString() + ") = True");
out.println("clsIsUnknown _ = False");
out.println("");
out.println("clsIToCls :: Int -> ClsType");
out.println("clsIToCls i = (C i 0)");
out.println("");
out.println("clsIToE :: Int -> Integer");
out.println("clsIToE 0 = error $ \"illegal classI: 0\"");
out.println("clsIToE " + numberThing + " = 0");
out.println("clsIToE " + numberNothing + " = " + clsNothingE.toString());
out.println("clsIToE " + numberNothingThing + " = " + clsNothingThingE.toString());
			for (Map.Entry<Integer,BigInteger> e : clsIToE.entrySet())
				out.println("clsIToE " + e.getKey().toString() + 
						" = " + e.getValue().toString());
out.println("clsIToE i = error $ \"illegal classI: \" ++ show i");
out.println("");
out.println("clsIBit :: Int -> Int");
out.println("clsIBit i = i - " + (numberSpecial + 1));
out.println("");
out.println("clsEToIs :: Integer -> [Int]");
out.println("clsEToIs 0 = [clsThingI]");
out.println("clsEToIs (-1) = [clsNothingI]");
out.println("clsEToIs "+clsNothingE.toString()+" = [clsNothingI]");
out.println("clsEToIs "+clsNothingThingE.toString()+" = [clsNothingThingI]");
out.println("clsEToIs e = opt (drop clsNSpecial clsGetAllI) e [] -- drop for thing and nothing");
out.println("	where");
out.println("		opt _ 0 acc = acc");
out.println("		opt [] j _ = error $ \"clsEToString illegal classE: \" ++ show j");
out.println("		opt _ j _ | j < 0 = error \"clsEToString illegal argument\"");
out.println("		opt (i:is) j acc = ");
out.println("			if testBit j (clsIBit i) then");
out.println("				let j' = j .&. complement (clsIToE i) in ");
out.println("					-- j >= 0, so j' >= 0");
out.println("				opt is j' (i:acc)");
out.println("			else opt is j acc");
out.println("");
out.println("clsEToCls :: Integer -> ClsType");
out.println("clsEToCls 0 = (C " + numberThing + " 0)");
out.println("clsEToCls (-1) = (C " + numberNothing + " 0)");
out.println("clsEToCls ("+clsNothingE.toString()+") = (C " + numberNothing + " 0)");
out.println("clsEToCls ("+clsNothingThingE.toString()+") = (C " + numberNothingThing + " 0)");
			for (Map.Entry<Integer,BigInteger> e : clsIToE.entrySet())
				out.println("clsEToCls " + e.getValue().toString() + 
						" = (C " + e.getKey().toString() + " 0)");
out.println("clsEToCls e = (C 0 e)");
out.println("");
out.println("------------------------------------------");
out.println("--  SHOW and READ");
out.println("------------------------------------------");
out.println("");
out.println("clsToString :: ClsType -> String");
out.println("clsToString (C i 0) = clsIToString i");
out.println("clsToString (C 0 e) = clsEToString e");
out.println("clsToString (C i e) = \"(C \" ++ show i ++ \" \" ++ show e ++ \")\"");
out.println("");
out.println("clsIToString :: Int -> String");
out.println("clsIToString 0 = \"(C 0 0)\"");
out.println("clsIToString " + numberThing + " = \"Thing\"");
out.println("clsIToString " + numberNothing + " = \"Nothing\"");
out.println("clsIToString " + numberThingNothing + " = \"ThingNothing\"");
out.println("clsIToString " + numberNothingThing + " = \"NothingThing\"");
out.println("clsIToString " + numberUnknown + " = \"Unknown\"");
			for (Map.Entry<OWLClass,Integer> e : clsCToI.entrySet())
				out.println("clsIToString " + e.getValue().toString() + " = \"" +
						e.getKey().getIRI().getFragment() + "\"");
out.println("clsIToString i = \"(C \" ++ show i ++ \" 0)\"");
out.println("");
out.println("clsEToString :: Integer -> String");
out.println("clsEToString e = show $ map clsIToCls $ clsEToIs e 	");
out.println("");
out.println("instance Show ClsType where");
out.println("	show c = clsToString c");
out.println("");
out.println("clsIFromString :: String -> RP.ReadPrec Int");
out.println("clsIFromString \"Thing\" = return " + numberThing);
out.println("clsIFromString \"Nothing\" = return " + numberNothing);
out.println("clsIFromString \"NothingThing\" = return " + numberNothingThing);
out.println("clsIFromString \"ThingNothing\" = return " + numberThingNothing);
out.println("clsIFromString \"Unknown\" = return " + numberUnknown);
			for (Map.Entry<OWLClass,Integer> e : clsCToI.entrySet())
				out.println("clsIFromString \"" + e.getKey().getIRI().getFragment() + "\" = return " +
						e.getValue().toString());
out.println("clsIFromString _ = RP.pfail");
out.println("");
out.println("clsToE :: ClsType -> Integer");
out.println("clsToE (C 0 0) = error $ \"illegal class: (C 0 0)\"");
out.println("clsToE (C i 0) = clsIToE i");
out.println("clsToE (C 0 e) = e");
out.println("");
out.println("clsNot :: ClsType -> ClsType");
out.println("clsNot (C i1 0) = clsNot (C 0 $ clsIToE i1)");
out.println("clsNot (C 0 e1) = ");
out.println("	let e3 = foldl clearBit (clsIToE clsNothingI) $ map clsIBit $ clsEToIs e1 in");
out.println("	let f e i =	");
out.println("		let ei = clsIToE i in");
out.println("		if ei .&. e == ei then e");
out.println("		else clearBit e (clsIBit i)");
out.println("	in clsEToCls $ foldl f e3 $ drop clsNSpecial clsGetAllI");
out.println("");
out.println("clsDomainI :: Int -> Integer");
out.println("clsDomainI i1 =");
out.println("	let e1 = clsIToE i1 in ");
out.println("	let f e i = ");
out.println("		let ei = clsIToE i in");
out.println("		if ei .&. e1 == e1 then e .|. ei else e");
out.println("	in foldl f e1 $ drop clsNSpecial clsGetAllI");
out.println("clsDomain :: ClsType -> ClsType");
out.println("clsDomain (C i1 0) = clsEToCls $ clsDomainI i1");
out.println("clsDomain (C 0 e1) = ");
out.println("	clsEToCls $ List.foldl1 (.|.) $ map clsDomainI (clsEToIs e1)");
out.println("");
out.println("clsInf ls = clsEToCls $ List.foldl1 (.|.) $ map clsToE ls");
out.println("clsSup ls = clsEToCls $ List.foldl1 (.&.) $ map clsToE ls");
out.println("");
out.println("instance Read ClsType where");
out.println("	readPrec = GR.parens $ readPrecOne RP.+++ readPrecList where");
out.println("		mod x = do");
out.println("			str <- RP.look");
out.println("			case str of");
out.println("				('~':_) -> do ");
out.println("					'~' <- RP.get");
out.println("					fmap clsNot $ GR.parens $ mod x");
out.println("				('@':_) -> do");
out.println("					'@' <- RP.get");
out.println("					fmap clsDomain $ GR.parens $ mod x");
out.println("				_ -> x");
out.println("		readPrecOne = mod $ do");
out.println("			Lex.Ident s <- GR.lexP");
out.println("			i <- clsIFromString s");
out.println("			return $ clsIToCls i");
out.println("		readPrecList = mod $ do");
out.println("			ls <- GR.list readPrecOne");
out.println("			return $ clsInf ls");
out.println("");
out.println("clsFromString :: String -> ClsType");
out.println("clsFromString s = read s");
out.println("");
		} catch (IOException e) {
			System.err.println(e);
		} finally {
			if (out != null) {
				out.flush();
				out.close();
			}
		}
	}

	public static void generateClsData() {
		PrintWriter out = null;
		try {
			out = new PrintWriter("ClsData.hs");

out.println("{-");
out.println(" -  Separ, Type/ClsData.hs");
out.println(" -");
out.println(" -  Copyright (c) 2010 Dariusz Leniowski. All Rights Reserved.");
out.println(" -");
out.println(" -  Redistribution and use in source and binary forms, with or without ");
out.println(" -  modification, are permitted provided that the following conditions ");
out.println(" -  are met:");
out.println(" -");
out.println(" -  1. Redistributions of source code must retain the above copyright ");
out.println(" -     notice, this list of conditions and the following disclaimer.");
out.println(" -");
out.println(" -  2. Redistributions in binary form must reproduce the above copyright ");
out.println(" -     notice, this list of conditions and the following disclaimer ");
out.println(" -     in the documentation and/or other materials provided with ");
out.println(" -     the distribution.");
out.println(" -");
out.println(" -  3. The name of the author may not be used to endorse or promote ");
out.println(" -     products derived from this software without specific prior ");
out.println(" -     written permission.");
out.println(" -");
out.println(" -  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ");
out.println(" -  \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ");
out.println(" -  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ");
out.println(" -  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ");
out.println(" -  THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, ");
out.println(" -  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ");
out.println(" -  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ");
out.println(" -  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ");
out.println(" -  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ");
out.println(" -  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING ");
out.println(" -  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ");
out.println(" -  POSSIBILITY OF SUCH DAMAGE.");
out.println(" -");
out.println(" -}");
out.println("");
out.println("{-# LANGUAGE TypeSynonymInstances #-}");
out.println("");
out.println("-- Module ClsData");
out.println("-- Autogenerated, do not edit");
out.println("");
out.println("module Type.ClsData where");
out.println("");
out.println("import Data.Bits");
out.println("import qualified Data.List as List");
out.println("import qualified Data.Set as Set");
out.println("import Type.Base");
out.println("import Type.ClsType");
out.println("");
out.println("----------------------------------------------");
out.println("--  some operators for types ");
out.println("----------------------------------------------");
out.println("");
out.println("infixl 5 <-- ");
out.println("infixr 5 --> ");
out.println("infixl 6 <<< ");
out.println("infixr 6 >>> ");
out.println("infixl 4 `is` ");
out.println("infixl 8 `sp` ");
out.println("infixl 8 `gp` ");
out.println("infix  9 `val` ");
out.println("infixl 7 `inf` ");
out.println("infixl 7 `sup` ");
out.println("");
out.println("class ConvertibleToType a where");
out.println("	toType :: a -> Type");
out.println("instance ConvertibleToType Int where");
out.println("	toType i = Ref i");
out.println("instance ConvertibleToType String where");
out.println("	toType s = Cls $ read s");
out.println("instance ConvertibleToType Type where");
out.println("	toType ty = ty");
out.println("");
out.println("(<--) :: (ConvertibleToType a, ConvertibleToType b) => a -> b -> Type");
out.println("r <-- a = Lam False (toType a) (toType r)");
out.println("(-->) :: (ConvertibleToType a, ConvertibleToType b) => a -> b -> Type");
out.println("a --> r = Lam True (toType a) (toType r)");
out.println("(>>>) :: (ConvertibleToType a, ConvertibleToType b) => a -> b -> Type");
out.println("x >>> f = App True (toType f) (toType x)");
out.println("(<<<) :: (ConvertibleToType a, ConvertibleToType b) => a -> b -> Type");
out.println("f <<< x = App False (toType f) (toType x)");
out.println("");
out.println("t :: Int -> (Int,Type)");
out.println("t i = (i,Cls clsThing)");
out.println("is :: ConvertibleToType a => (Int,Type) -> a -> (Int,Type)");
out.println("is (i,_) ty = (i,toType ty)");
out.println("sp :: ConvertibleToType a => a -> (String,Type) -> Type");
out.println("sp ty (s,p) = pSet (toType ty) s p");
out.println("val :: ConvertibleToType a => String -> a -> (String,Type)");
out.println("val s p = (s,toType p)");
out.println("gp :: ConvertibleToType a => a -> String -> Type");
out.println("gp ty s = PGet (toType ty) s");
out.println("sup :: (ConvertibleToType a, ConvertibleToType b) => a -> b -> Type");
out.println("sup a b = Lca (toType a) (toType b)");
out.println("inf :: (ConvertibleToType a, ConvertibleToType b) => a -> b -> Type");
out.println("inf a b = Gcd (toType a) (toType b)");
out.println("");
out.println("var :: ConvertibleToType a => [(Int,Type)] -> a -> Type");
out.println("var ls ty = foldr (\\(i,t1) t2 -> Var i (Cls clsNothing,t1) TT t2) (toType ty) ls");
out.println("");
out.println("");
out.println("----------------------------------------------");
out.println("--  relations on classes");
out.println("----------------------------------------------");
out.println("");
out.println("clsGetSubclasses :: ClsType -> [ClsType]");
out.println("clsGetSubclasses c@(C 0 0) = error $ \"illegal class: \" ++ show c");
			for (Integer i = new Integer(1); i <= clsN; i++)
				out.println("clsGetSubclasses   (C " + i.toString() + " 0) = map clsIToCls " +
						clsISub.get(i).toString());
out.println("clsGetSubclasses c@(C _ 0) = error $ \"illegal class: \" ++ show c");
out.println("clsGetSubclasses   (C 0 e) = map clsIToCls $ clsEToIs e");
out.println("clsGetSubclasses c@(C _ _) = error $ \"illegal class: \" ++ show c");
out.println("");
out.println("clsGetSuperclasses :: ClsType -> [ClsType]");
out.println("clsGetSuperclasses c@(C 0 0) = error $ \"illegal class: \" ++ show c");
			for (Integer i = 1; i <= clsN; i++)
				out.println("clsGetSuperclasses   (C " + i.toString() + " 0) = map clsIToCls " +
						clsISuper.get(i).toString());
out.println("clsGetSuperclasses c@(C _ 0) = error $ \"illegal class: \" ++ show c");
out.println("clsGetSuperclasses   (C 0 e) = ");
out.println("	let f i = clsIsSubclassOf (C 0 e) (C i 0) in");
out.println("	map clsIToCls $ List.filter f clsGetAllI");
out.println("clsGetSuperclasses c@(C _ _) = error $ \"illegal class: \" ++ show c");
out.println("");
out.println("clsGetAllSuperclasses :: ClsType -> [ClsType]");
out.println("clsGetAllSuperclasses c = Set.toList $ f Set.empty $ clsGetSuperclasses c where");
out.println("	f out []  = out");
out.println("	f out inp = ");
out.println("		let sinp = Set.fromList inp in");
out.println("		let inp' = Set.toList $ Set.difference sinp out in ");
out.println("		f (Set.union out sinp) $ List.concatMap clsGetSuperclasses inp'");
out.println("");
out.println("clsGetValues :: ClsType -> Type -> [Type]");
			for (Integer i = new Integer(1); i <= clsN; i++) {
				Set s = clsValues.get(i);
				if (!s.isEmpty())
					out.println("clsGetValues (C " + i.toString() + " 0) self = " + s.toString());
			}
out.println("clsGetValues _ _ = []");
out.println("");
out.println("clsGetSubtype :: ClsType -> Type -> MM Type");
out.println("clsGetSubtype cls org | clsIsThing cls = fail $ \"\"");
out.println("clsGetSubtype cls org = MM $ \\ctx -> ");
out.println("	map (\\ty -> (ctx,ty)) $ concatMap (flip clsGetValues org) $ cls:(clsGetAllSuperclasses cls)"); 
out.println("");
out.println("clsGetProperties :: String -> ClsType -> Type -> [Type]");
			for (Integer i = new Integer(1); i <= clsN; i++) {
				Map<String,Set<String>> s = clsProperties.get(i);
				for (Map.Entry<String,Set<String>> e : s.entrySet())
					if (!e.getValue().isEmpty())
						out.println("clsGetProperties \"" + escape(e.getKey()) + "\"" +
								" (C " + i.toString() + " 0) self = " + e.getValue().toString());
			}
out.println("clsGetProperties _ _ _ = []");
out.println("");
out.println("clsGetProperty :: String -> ClsType -> Type -> MM Type");
out.println("clsGetProperty s cls org = MM $ \\ctx -> ");
out.println("	map (\\ty -> (ctx,ty)) $ ");
out.println("		concatMap (flip (clsGetProperties s) org) $ ");
out.println("			cls:(clsGetAllSuperclasses cls)");
out.println("");
out.println("clsGetComments :: ClsType -> [String]");
			for (Integer i = new Integer(1); i <= clsN; i++) {
				Set s = clsComments.get(i);
				if (!s.isEmpty())
					out.println("clsGetComments (C " + i.toString() + " 0) = " + s.toString());
			}
out.println("clsGetComments _ = []");
out.println("");
out.println("clsGetAnnotations :: ClsType -> [(String,String)]");
			for (Integer i = new Integer(1); i <= clsN; i++) {
				Set s = clsAnnotations.get(i);
				if (!s.isEmpty())
					out.println("clsGetAnnotations (C " + i.toString() + " 0) = " + s.toString());
			}
out.println("clsGetAnnotations _ = []");
out.println("");
out.println("-- isSubclassOf(x,x)");
out.println("-- isSubclassOf(Int,Number)");
out.println("clsIsSubclassOf :: ClsType -> ClsType -> Bool");
out.println("clsIsSubclassOf (C 0 0) (C 0 0) = ");
out.println("	error $ \"illegal classes: (C 0 0) (C 0 0)\"");
out.println("clsIsSubclassOf (C 0 0) _ = error $ \"illegal class: (C 0 0)\"");
out.println("clsIsSubclassOf _ (C 0 0) = error $ \"illegal class: (C 0 0)\"");
out.println("clsIsSubclassOf (C "+numberThing+" 0) (C "+numberThing+" 0) = True"); // thing
out.println("clsIsSubclassOf (C "+numberNothing+" 0) (C "+numberNothing+" 0) = True"); // nothing
out.println("clsIsSubclassOf (C "+numberNothingThing+" 0) (C "+numberNothingThing+" 0) = True"); // nothingthing
out.println("clsIsSubclassOf (C "+numberNothingThing+" 0) (C "+numberThingNothing+" 0) = False");
out.println("clsIsSubclassOf (C "+numberThingNothing+" 0) (C "+numberThingNothing+" 0) = True"); // thingnothing
out.println("clsIsSubclassOf (C "+numberThingNothing+" 0) (C "+numberNothingThing+" 0) = False");
out.println("clsIsSubclassOf (C "+numberThingNothing+" 0) (C "+numberThing+" 0) = True");
out.println("clsIsSubclassOf (C "+numberThing+" 0) (C _ 0) = False");
out.println("clsIsSubclassOf (C _ 0) (C "+numberThing+" 0) = True");
out.println("clsIsSubclassOf (C "+numberNothing+" 0) (C _ 0) = True");
out.println("clsIsSubclassOf (C _ 0) (C "+numberNothing+" 0) = False");
out.println("clsIsSubclassOf (C "+numberNothingThing+" 0) (C _ 0) = True");
out.println("clsIsSubclassOf (C _ 0) (C "+numberNothingThing+" 0) = False");
out.println("clsIsSubclassOf (C "+numberThingNothing+" 0) (C _ 0) = False");
out.println("clsIsSubclassOf (C i1 0) (C i2 0) = ");
out.println("	let e1 = clsIToE i1 in");
out.println("	let e2 = clsIToE i2 in");
out.println("	e1 .&. e2 == e2");
out.println("clsIsSubclassOf (C i1 0) (C 0 e2) = let e1 = clsIToE i1 in e1 .&. e2 == e2");
out.println("clsIsSubclassOf (C 0 e1) (C i2 0) = let e2 = clsIToE i2 in e1 .&. e2 == e2");
out.println("clsIsSubclassOf (C 0 e1) (C 0 e2) = e1 .&. e2 == e2");
out.println("clsIsSubclassOf c1@(C _ _) c2@(C _ _) = ");
out.println("	error $ \"illegal classes: \" ++ show c1 ++ \" and \" ++ show c2");
out.println("");
out.println("clsIsProperSubclassOf :: ClsType -> ClsType -> Bool");
out.println("clsIsProperSubclassOf c1 c2 = clsIsSubclassOf c1 c2 && (c1 /= c2)");
out.println("");

		} catch (IOException e) {
			System.err.println(e);
		} finally {
			if (out != null) {
				out.flush();
				out.close();
			}
		}

	}
	
	public static void generateClsDict() {
		PrintWriter out = null;
		try {
			out = new PrintWriter("ClsDict.hs");
			out.println("{-");
			out.println(" -  Separ, Type/ClsDict.hs");
			out.println(" -");
			out.println(" -  Copyright (c) 2010 Dariusz Leniowski. All Rights Reserved.");
			out.println(" -");
			out.println(" -  Redistribution and use in source and binary forms, with or without ");
			out.println(" -  modification, are permitted provided that the following conditions ");
			out.println(" -  are met:");
			out.println(" -");
			out.println(" -  1. Redistributions of source code must retain the above copyright ");
			out.println(" -     notice, this list of conditions and the following disclaimer.");
			out.println(" -");
			out.println(" -  2. Redistributions in binary form must reproduce the above copyright ");
			out.println(" -     notice, this list of conditions and the following disclaimer ");
			out.println(" -     in the documentation and/or other materials provided with ");
			out.println(" -     the distribution.");
			out.println(" -");
			out.println(" -  3. The name of the author may not be used to endorse or promote ");
			out.println(" -     products derived from this software without specific prior ");
			out.println(" -     written permission.");
			out.println(" -");
			out.println(" -  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ");
			out.println(" -  \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ");
			out.println(" -  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ");
			out.println(" -  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ");
			out.println(" -  THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, ");
			out.println(" -  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ");
			out.println(" -  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ");
			out.println(" -  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ");
			out.println(" -  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ");
			out.println(" -  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING ");
			out.println(" -  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ");
			out.println(" -  POSSIBILITY OF SUCH DAMAGE.");
			out.println(" -");
			out.println(" -}");
			out.println("");
			out.println("-- Module ClsDict");
			out.println("-- Autogenerated, do not edit");
			out.println("");
			out.println("module Type.ClsDict where");
			out.println("");
			out.println("import Data.Char");
			out.println("import Data.List");
			out.println("import Type.ClsType");
			out.println("import Type.Base");
			out.println("");
			out.println("dictionary :: String -> [Type]");
			out.println("dictionary \"TypeThing\" = [Cls (C " + numberThing + " 0)]");
			out.println("dictionary \"TypeNothing\" = [Cls (C " + numberNothing + " 0)]");
			out.println("dictionary \"TypeNothingThing\" = [Cls (C " + numberNothingThing + " 0)]");
			out.println("dictionary \"TypeThingNothing\" = [Cls (C " + numberThingNothing + " 0)]");
			out.println("dictionary \"TypeUnknown\" = [Cls (C " + numberUnknown + " 0)]");
			for (Map.Entry<String,Set<Integer>> e : indTypes.entrySet()) {
				e.getValue().remove(new Integer(1));
				Set<String> es = indExprs.get(e.getKey());
				if (es.isEmpty()) out.println("dictionary \"" + escape(e.getKey()) + 
						"\" = map (Cls .clsIToCls) " + e.getValue().toString());
				else out.println("dictionary \"" + escape(e.getKey()) + 
						"\" = map read " + indExprs.get(e.getKey()) + 
						" ++ map (Cls . clsIToCls) " + e.getValue().toString());
			}
			out.println("dictionary ('-':n) | let n' = delete '.' n in and [not $ null n', all isNumber n'] = [read \"Number\"]");
			out.println("dictionary      n  | let n' = delete '.' n in and [not $ null n', all isNumber n'] = [read \"Number\"]");
			out.println("dictionary _ = [read \"Unknown\"]");
			out.println("");
		} catch (IOException e) {
			System.err.println(e);
		} finally {
			if (out != null) {
				out.flush();
				out.close();
			}
		}
	}
	
	public static String escape(String s) {
		return s.replace("\n","\\n").replace("\"","\\\"");
	}

	public static IRI getIRI(String name) {
		return IRI.create(base + "#" + name);
	}

	public static String getName(URI uri) {
		String whole = uri.toString();
		String s1 = "http://www.w3.org/2000/01/rdf-schema#";
		String s2 = "http://www.w3.org/2006/12/owl2-xml#";
		String s3 = "http://www.w3.org/2002/07/owl#";
		String s4 = "http://www.w3.org/2001/XMLSchema#";
		String s5 = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
		if (whole.startsWith(base + "#")) {
			return whole.substring(base.toString().length() + 1);
		} else if (whole.startsWith(s1)) {
			return whole.substring(s1.toString().length());
		} else if (whole.startsWith(s2)) {
			return whole.substring(s2.toString().length());
		} else if (whole.startsWith(s3)) {
			return whole.substring(s3.toString().length());
		} else if (whole.startsWith(s4)) {
			return whole.substring(s4.toString().length());
		} else if (whole.startsWith(s5)) {
			return whole.substring(s5.toString().length());
		} else {
			throw new IllegalArgumentException("Couldn't decipher name from: " + whole);
		}
	}

	public static String getLiteral(OWLAnnotation annotation) {
		if (annotation.getValue() instanceof OWLLiteral) {
			OWLLiteral val = (OWLLiteral) annotation.getValue();
			return val.getLiteral();
		} else throw new IllegalArgumentException(
				"Annotation with non-literal value: " + 
				annotation.getValue().toString());		
	}

	public static Set<String> getAnnotations(OWLClass owlClass) {
		Set<OWLAnnotation> annSet = owlClass.getAnnotations(ontology);
		Set<String> result = new TreeSet();
		if (annSet != null) for (OWLAnnotation annotation : annSet) {
			String name = annotation.getProperty().getIRI().getFragment();
			String value = getLiteral(annotation);
			result.add("(\"" + escape(name) + "\",\"" + escape(value) + "\")");
		}
		return result;
	}

	public static Set<String> getAnnotation(OWLClass owlClass,String name) {
		Set<OWLAnnotation> annSet = owlClass.getAnnotations(ontology, getOWLAnnotationProperty(name));
		Set<String> result = new TreeSet();
		if (annSet != null) for (OWLAnnotation annotation : annSet) {
			result.add(getLiteral(annotation));
		}
		return result;
	}

	public static Set<String> getValues(OWLClass owlClass) {
		Set<OWLAnnotation> annSet = owlClass.getAnnotations(ontology, getOWLAnnotationProperty("value"));
		Set<String> result = new TreeSet();
		if (annSet != null) for (OWLAnnotation annotation : annSet) {
			result.add(sValue(getLiteral(annotation)));
		}
		return result;
	}

	public static Set<String> getComments(OWLClass owlClass) {
		Set<OWLAnnotation> annSet = owlClass.getAnnotations(ontology, 
				dataFactory.getOWLAnnotationProperty(OWLRDFVocabulary.RDFS_COMMENT.getIRI()));
		Set<String> result = new TreeSet();
		if (annSet != null) for (OWLAnnotation annotation : annSet) {
			result.add("\"" + escape(getLiteral(annotation))+"\"");
		}
		return result;
	}

	public static Map<String,Set<String>> getProperties(OWLClass owlClass) {
		Map<String,Set<String>> result = new TreeMap<String,Set<String>>();
		Set<OWLAnnotation> annSet = owlClass.getAnnotations(ontology, getOWLAnnotationProperty("property"));
		if (annSet != null) for (OWLAnnotation annotation : annSet) {
			String[] s = getLiteral(annotation).split("=",2);
			String key = s[0].trim();
			String value = s[1].trim();
			if (key.length() == 0 || value.length() == 0) continue;
			if (result.get(key) == null) result.put(key,new TreeSet<String>());
			result.get(key).add(sValue(value));
		}
		return result;
	}

	public static OWLDataProperty getOWLDataProperty(String name) {
		return dataFactory.getOWLDataProperty(getIRI(name));
	}

	public static OWLAnnotationProperty getOWLAnnotationProperty(String name) {
		return dataFactory.getOWLAnnotationProperty(getIRI(name));
	}

	public static Set<OWLClass> getIndividualTypes(OWLIndividual owlIndividual) {
		Set<OWLClassExpression> descSet = owlIndividual.getTypes(ontology);
		Set<OWLClass> clsSet = new HashSet<OWLClass>();
		for (OWLClassExpression desc : descSet) {
			clsSet.add(desc.asOWLClass());
		}
		return clsSet;
	}

	public static Set<String> getIndividualProperty(OWLIndividual owlIndividual, String name) {
		OWLDataPropertyExpression property = getOWLDataProperty(name);
		Set<OWLLiteral> conSet = owlIndividual.getDataPropertyValues(ontology).get(property);
		Set<String> result = new TreeSet();
		if (conSet != null) for (OWLLiteral con : conSet) result.add(con.getLiteral());
		return result;
	}

	public static <T> T any(Collection<? extends T> coll) {
		for (T t : coll) return t;
		throw new IllegalArgumentException("Empty collection!");
	}
}
